home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-03 | 32.2 KB | 1,143 lines | [TEXT/MPS ] |
- //----------------------------------------------------------------------------------------
- // USegments.cp
- // Copyright © 1995-96 by Apple Computer, Inc. All rights reserved.
- //----------------------------------------------------------------------------------------
-
- #ifndef __USEGMENTS__
- #include "USegments.h"
- #endif
-
- #if qSegments
-
- // MacApp
-
- #ifndef __UDEBUG__
- #include "UDebug.h"
- #endif
-
- #ifndef __UFAILURE__
- #include "UFailure.h"
- #endif
-
- #ifndef __UCOREUTILITIES__
- #include "UCoreUtilities.h"
- #endif
-
- #ifndef __UMEMORY__
- #include "UMemory.h"
- #endif
-
- #ifndef __UNIVERSALSTARTUP__
- #include "UniversalStartup.h"
- #endif
-
- #ifndef __UPATCH__
- #include "UPatch.h"
- #endif
-
- // OpenDoc
-
- #ifndef _MEMMGR_
- #include "MemMgr.h"
- #endif
-
- // Toolbox
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __LOWMEM__
- #include <LowMem.h>
- #endif
-
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #if (qModelFarCode || qModelCFM) && !defined(__MWERKS__)
- #define qUseRTLib TRUE
- #else
- #define qUseRTLib FALSE
- #endif
-
- #if qUseRTLib
- #ifndef __RTLIB__
- #include "RtLib.h"
- #endif
- #endif
-
- #ifndef __SEGLOAD__
- #include <SegLoad.h>
- #endif
-
- #ifndef __TRAPS__
- #include <Traps.h>
- #endif
-
- // ANSI
-
- #ifndef __LIMITS__
- #include <limits.h>
- #endif
-
- #if qDebugMsg
- #ifndef __STDIO__
- #include <stdio.h>
- #endif
- #endif
-
- //----------------------------------------------------------------------------------------
- // CLASS CCodeSegmentGrowZoneHook
- //----------------------------------------------------------------------------------------
-
- class CCodeSegmentGrowZoneHook : public CGrowZoneHook
- {
- public:
- CCodeSegmentGrowZoneHook();
- virtual ~CCodeSegmentGrowZoneHook();
-
- virtual Size TotalSize(Boolean justLocked);
- // Returns the total number of bytes of the code segments currently in RAM
- // (or only locked segments if justLocked is true).
-
- virtual Size Purge(Size needed);
- // Make memory available by emptying code segment handles. Returns the actual
- // amount of memory purged.
- };
-
- //----------------------------------------------------------------------------------------
- // Constants
- //----------------------------------------------------------------------------------------
-
- const short kHeapOverhead = 8;
-
- //----------------------------------------------------------------------------------------
- // Globals to this module and externally available.
- //----------------------------------------------------------------------------------------
-
- CCodeSegment* gCodeSegs; // includes seg 0 which is unused.
- Boolean gUnloadAllSegs = TRUE;
- short pMaxSegNum; // has extern
-
- #if !qModelCFM
- TrapPatch pSegLoadPatch; // has extern
- #endif
-
- short pOldResFile; // has extern
-
- Boolean pLoadSegCalledFromOwnApp; // has extern
-
- // local private globals
- #if qUseRTLib
- static SegLoadHdlrPtr oldPreLoadHandler;
- static SegLoadHdlrPtr oldPostLoadHandler;
- #endif
-
- // LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls LoadMacAppSegment.
- // ALoadMacAppSeg can only be referenced as a procedure pointer, because no args are
- // declared
-
- #if qUseRTLib
- typedef pascal short(* HandlerType)(RTState* state);
- #endif
-
- // Memory hook for our unit
- CCodeSegmentGrowZoneHook gCodeSegmentGrowZoneHook;
-
- #if qDebug
- unsigned long CCodeSegment::gHighWater;
- #endif
-
- //========================================================================================
- // EXTERNAL Procedures
- //========================================================================================
-
- #if defined(__MWERKS__)
- extern pascal Boolean PreloadSegment(short theSegNum);
- // In UMemory.More.CW.cp
- #endif
-
- extern pascal void ALoadMacAppSeg();
- // Function prototype for the routine in UMemory.a
-
- //========================================================================================
- // GLOBAL Procedures
- //========================================================================================
-
- extern pascal void PostLoadMacAppSegment(); // referenced by UMemory.a
-
- static void DoInitUSegments(Size& sizeTempReserve);
-
- static void CheckCallChain(const CStackFrame& frame,
- void* /* yourDataPtr */ );
-
- static CCodeSegment* GetCodeSegmentFromName(const CStr255& name);
-
- //----------------------------------------------------------------------------------------
- // GetCodeSegmentFromID:
- //----------------------------------------------------------------------------------------
-
- static inline CCodeSegment* GetCodeSegmentFromID(short segNumber)
- {
- return gCodeSegs + segNumber;
- }
-
- //----------------------------------------------------------------------------------------
- // InlineIsHandlePurged:
- //----------------------------------------------------------------------------------------
-
- static inline Boolean InlineIsHandlePurged(Handle h)
- // don't use IsHandlePurged, it may be in an unloaded segment
- {
- return *h == NULL;
- }
-
- //----------------------------------------------------------------------------------------
- // InlineIsHandleEligible:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- static inline Boolean InlineIsHandleEligible(Handle h)
- {
- // SRF rewrote as single expression and only used documented approved
- // interface for GZSaveHnd
- return h && (*h != NULL) && (h != GZSaveHnd());
- }
-
- //========================================================================================
- // CLASS CCodeSegmentGrowZoneHook
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // CCodeSegmentGrowZoneHook constructor:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- CCodeSegmentGrowZoneHook::CCodeSegmentGrowZoneHook()
- {
- }
-
- //----------------------------------------------------------------------------------------
- // CCodeSegmentGrowZoneHook destructor:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- CCodeSegmentGrowZoneHook::~CCodeSegmentGrowZoneHook()
- {
- }
-
- //----------------------------------------------------------------------------------------
- // CCodeSegmentGrowZoneHook::TotalSize:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMemoryRes
-
- Size CCodeSegmentGrowZoneHook::TotalSize(Boolean justLocked)
- {
- Size total = 0;
- for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- {
- Handle h = codeSegment->fCodeSeg;
- if (h && !InlineIsHandlePurged(h)) // in memory already
- {
- //HNoPurge(h);
- if (!justLocked || IsHandleLocked(h))
- total += codeSegment->GetSize() + kHeapOverhead;
- }
- }
- return total;
- } // CCodeSegmentGrowZoneHook::TotalSize
-
- //----------------------------------------------------------------------------------------
- // CCodeSegmentGrowZoneHook::Purge:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMemoryRes
-
- Size CCodeSegmentGrowZoneHook::Purge(Size needed)
- {
- Size purged = 0;
- for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- {
- Handle h = codeSegment->fCodeSeg;
- if (InlineIsHandleEligible(h) && !IsHandleLocked(h))
- {
- purged += codeSegment->GetSize();
- EmptyAHandle(h);
- if (purged >= needed)
- break;
- }
- }
- return purged;
- } // CCodeSegmentGrowZoneHook::Purge
-
- //========================================================================================
- // CLASS CCodeSegment
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // GetSegResource:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- Handle CCodeSegment::GetSegResource()
- {
- return MAGet1Resource(kCode, fSegNum);
- } // GetSegResource
-
- //----------------------------------------------------------------------------------------
- // IsSegmentLoaded: Returns whether the segment
- // is in a loaded (true) or unloaded(false) state.
- //
- // IsSegmentLoaded must be in Main segment because we call this in order to make the
- // resident segment resident.
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- Boolean CCodeSegment::IsSegmentLoaded()
- {
- Boolean returnVal = FALSE;
-
- static const short kLoaded = 0x4EF9; // if loaded then a JMP instruction
-
- if (fSegNum != 0) // don't care about special zero segment
- {
- #if defined(__MWERKS__)
- if (fSegNum < 2)
- returnVal = TRUE;
- else
- #endif
- if (*fCodeSeg && (*((const short *)((long)this->GetFirstFunctionPointer())) == kLoaded))
- returnVal = TRUE;
- }
-
- return returnVal;
- } // IsSegmentLoaded
-
- //----------------------------------------------------------------------------------------
- // GetSize:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- Size CCodeSegment::GetSize()
- {
- if (fSegSize == -1)
- {
- if (fCodeSeg && !InlineIsHandlePurged(fCodeSeg))
- fSegSize = InlineGetHandleSize(fCodeSeg);
- else
- fSegSize = GetResourceSizeOnDisk(fCodeSeg);
- }
- return fSegSize;
- } // GetSize
-
- //----------------------------------------------------------------------------------------
- // CCodeSegment::LoadMacAppSegment:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // must be in Main segment
-
- void CCodeSegment::LoadMacAppSegment()
- {
- if (!this->PreloadSegmentResource())
- {
- #if qDebug
- DebugStr((StringPtr)"\pFailure in CCodeSegment::LoadMacAppSegment");
- #endif
- Failure(memFullErr, 0);
- }
-
- fSegLoaderLoaded = TRUE;
-
- #if qDebug
- if (gSegReport)
- {
- short id;
- ResType kind;
- CStr255 segName;
- MAName s;
-
- GetResInfo(fCodeSeg, &id, &kind, segName);
- fprintf(stderr, " *** Segment Loaded: %d %s\n", fSegNum, (const char*)segName);
- }
- #endif
- } // LoadMacAppSegment
-
- //----------------------------------------------------------------------------------------
- // PreloadSegmentResource:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // must be in Main segment
-
- pascal Boolean PreloadSegmentResource(short segNum)
- {
- return GetCodeSegmentFromID(segNum)->PreloadSegmentResource();
- }
-
- //----------------------------------------------------------------------------------------
- // PreloadSegmentResource:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // must be in Main segment
-
- Boolean CCodeSegment::PreloadSegmentResource()
- {
- Boolean returnVal = FALSE;
-
- if (fSegLoaderLoaded)
- returnVal = TRUE;
- else
- {
- short oldResFile = MAUseResFile(gCodeRefNum);
-
- Boolean saveResLoad = MASetResLoad(TRUE); // yes, we really *do* want it.
-
- Boolean priorTemp = TemporaryAllocation(TRUE);// Code segments are temp
- Handle seg = MAGet1Resource(kCode, fSegNum);
- TemporaryAllocation(priorTemp);
-
- SetResLoad(saveResLoad);
-
- MAUseResFile(oldResFile);
-
- if (seg)
- {
- HNoPurge(seg);
- #if !defined(__MWERKS__)
- if (!IsHandleLocked(seg)) // not yet locked
- LockHandleHigh(seg);
- #endif
- returnVal = TRUE;
- }
- }
-
-
- #if qDebug
- fEverLoaded = TRUE;
-
- Size total = 0;
- {
- for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- if (codeSegment->fSegLoaderLoaded)
- total += codeSegment->GetSize() + kHeapOverhead;
- }
-
- if (total > gHighWater)
- {
- gHighWater = total;
-
- for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- codeSegment->fHighWater = codeSegment->fSegLoaderLoaded;
- }
- #endif
-
- return returnVal;
- } // PreloadSegmentResource
-
- //----------------------------------------------------------------------------------------
- // SetResidentSegment:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- // must be in Main segment
-
- void CCodeSegment::SetResidentSegment(Boolean makeResident)
- {
- if (makeResident)
- {
- fResidentSeg = TRUE;
- if (!this->IsSegmentLoaded())
- {
- // Load the segment resource, no need to call LoadSeg now
- #if defined(__MWERKS__)
- if (PreloadSegment(fSegNum))
- #else
- if (this->PreloadSegmentResource())
- #endif
- fSegLoaderLoaded = TRUE;
- else
- Failure(memFullErr, 0);
- }
- }
- else
- fResidentSeg = FALSE;
- } // SetResidentSegment
-
- //----------------------------------------------------------------------------------------
- // IsModelFar:
- //----------------------------------------------------------------------------------------
- #ifdef __MWERKS__
- const short kJTSkipOver = 4; //for large model, CW looks at the 2nd long in the resource
- #else
- const short kJTSkipOver = 2; // size of jmp (or loadseg) instruction
- // that must be skipped in the JT Entry in
- // order to get to the target address
- #endif
-
- struct ModelFarCodeHeader
- {
- short field1;
- short field2;
- long A5OffsetOf16BitEntries;
- long numOf16BitEntries;
- long A5OffsetOf32BitEntries;
- long numOf32BitEntries;
- char otherEvenMorePrivateStuff; // You didn't think I would reveal any more
- // than I had to did you?
- };
-
- typedef ModelFarCodeHeader ** ModelFarCodeHeaderHandle;
-
- #pragma segment Main
-
- Boolean CCodeSegment::IsModelFar()
- {
- #ifdef __MWERKS__
- return FALSE;
- #else
- static const short kModelFarFlag = 0xFFFF;
- return fCodeSeg && (*(ModelFarCodeHeaderHandle)fCodeSeg)->field1 == kModelFarFlag;
- #endif // __MWERKS__
- } // IsModelFar
-
- //----------------------------------------------------------------------------------------
- // IsModelCFM:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- #if qModelCFM
-
- Boolean CCodeSegment::IsModelCFM()
- {
- static const short kModelCFMFlag = 0xFFFD;
- return fCodeSeg && (*(ModelFarCodeHeaderHandle)fCodeSeg)->field1 == kModelCFMFlag;
- } // IsModelCFM
-
- #endif // qModelCFM
-
- //----------------------------------------------------------------------------------------
- // GetFirstFunctionPointer:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- Ptr CCodeSegment::GetFirstFunctionPointer()
- {
- Ptr unloadPtr;
-
- long* jmpTablePtr = (long*)(GetA5() + LMGetCurJTOffset());
-
- #if qModelCFM
- if (this->IsModelCFM())
- {
- unloadPtr = (Ptr)(jmpTablePtr + (*((ModelFarCodeHeaderHandle)fCodeSeg))->A5OffsetOf16BitEntries + kJTSkipOver);
- }
- #else
- if (this->IsModelFar())
- {
- if ((*((ModelFarCodeHeaderHandle)fCodeSeg))->numOf16BitEntries)
- unloadPtr = (Ptr)(jmpTablePtr + (*((ModelFarCodeHeaderHandle)fCodeSeg))->A5OffsetOf16BitEntries + kJTSkipOver);
- else // Has to be the other since we wouldn't even have a segment otherwise
- unloadPtr = (Ptr)(jmpTablePtr + (*((ModelFarCodeHeaderHandle)fCodeSeg))->A5OffsetOf32BitEntries + kJTSkipOver);
- }
- #endif // qModelCFM
- else
- {
- // Model near
- #ifdef __MWERKS__
- unloadPtr = (Ptr)((*(long*)((*fCodeSeg) + kJTSkipOver)) + (long)GetA5());
- #else
- unloadPtr = (Ptr)(jmpTablePtr + **((IntegerHandle)fCodeSeg) + kJTSkipOver);
- #endif
- }
-
- return unloadPtr;
- }
-
- //----------------------------------------------------------------------------------------
- // GetFirstFunctionPointer:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- void CCodeSegment::Unload()
- {
- UnloadSeg(this->GetFirstFunctionPointer());
- HNoPurge(this->fCodeSeg); // UnloadSeg made it purgeable
-
- fSegLoaderLoaded = FALSE;
- }
-
- //----------------------------------------------------------------------------------------
- // ContainsAddress:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- Boolean CCodeSegment::ContainsAddress(void* address)
- {
- short returnVal = FALSE;
-
- if (fCodeSeg && !InlineIsHandlePurged(fCodeSeg)) // it's in memory
- {
- long segStart = StripLong(*fCodeSeg);// get segment start
- if (((long)address >= segStart) && ((long)address < segStart + this->GetSize()))
- returnVal = TRUE;
- }
-
- return returnVal; // default return
- }
-
- //========================================================================================
- // GLOBAL Procedures
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // GetCodeSegmentFromName:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- CCodeSegment* GetCodeSegmentFromName(const CStr255& name)
- {
- CCodeSegment* returnVal = NULL;
-
- Boolean oldResLoad = MASetResLoad(FALSE);
- Handle seg = MAGet1NamedResource(kCode, name);
- if (seg)
- {
- short rsrcID;
- ResType rsrcType;
- CStr255 rsrcName;
- GetResInfo(seg, &rsrcID, &rsrcType, rsrcName);
-
- returnVal = GetCodeSegmentFromID(rsrcID);
- }
- SetResLoad(oldResLoad);
-
- return returnVal;
- }
-
- //----------------------------------------------------------------------------------------
- // AddSegSizes:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- Size AddSegSizes(Handle nameList)
- {
- SignedByte savedState = LockHandle(nameList);
-
- Ptr nameListPtr = *nameList;
- short numStrings = *((short*)nameListPtr);
- nameListPtr += sizeof(short);
-
- register long total = 0;
-
- for (; numStrings; --numStrings, nameListPtr += *nameListPtr + 1)
- {
- // count once and only once
- CCodeSegment* codeSegment = GetCodeSegmentFromName((CStr255&)*nameListPtr);
- if (codeSegment && !codeSegment->fInTemporaryReserve)
- {
- codeSegment->fInTemporaryReserve = TRUE;
- total += codeSegment->GetSize() + kHeapOverhead;
- }
- }
-
- HSetState(nameList, savedState);
-
- return total;
- } // AddSegSizes
-
- //----------------------------------------------------------------------------------------
- // DoInitUSegments: Called from InitUSegments so that InitUSegments can be in the main segment
- // and this code can be in another (unloadable) segment.
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- void DoInitUSegments(Size& temporaryReserve)
- {
- //###########################################
- // No resource loading
-
- Boolean oldResLoad = MASetResLoad(FALSE);
-
- // Figure the highest segment number
- // some development systems may not have contiguous numbering of CODE segments. try to
- // be polite about handling it
- // we only have an index find the real resource ID and keep track of the highest one
-
- short lastRsrc = MACount1Resources(kCode);
- for (short rsrcIndex = 1; rsrcIndex <= lastRsrc; ++rsrcIndex)
- {
- Handle seg = MAGet1IndResource(kCode, rsrcIndex);
-
- if (seg)
- {
- short rsrcID;
- ResType rsrcType;
- CStr255 rsrcName;
- GetResInfo(seg, &rsrcID, &rsrcType, rsrcName);
- pMaxSegNum = (short)Max(rsrcID, pMaxSegNum);
- }
- }
-
- SetResLoad(oldResLoad); // in case of failure
-
- // Allocate the master segment list.
- gCodeSegs = (CCodeSegment*)NewPtr((pMaxSegNum + 1) * sizeof(CCodeSegment));
- FailNIL(gCodeSegs);
-
- oldResLoad = MASetResLoad(FALSE);
-
- // Segments and their sizes and actual loaded state (helps catch preloads)
-
- CCodeSegment* prevSegPtr = NULL;
- short i = 0;
- for (CCodeSegment* codeSegment = GetCodeSegmentFromID(i); i <= pMaxSegNum; codeSegment = GetCodeSegmentFromID(++i))
- {
- codeSegment->fSegNum = i;
- codeSegment->fResidentSeg = FALSE;
- codeSegment->fInTemporaryReserve = FALSE;
- codeSegment->fCodeSeg = codeSegment->GetSegResource();
- codeSegment->fSegLoaderLoaded = FALSE;
- codeSegment->fSegSize = -1;
-
- codeSegment->fCanUnload = !(GetResAttrs(codeSegment->fCodeSeg) & resPreload); // don't unload the preloads
-
- if (codeSegment->fCodeSeg)
- {
- codeSegment->fSegLoaderLoaded = codeSegment->IsSegmentLoaded();
- if (!InlineIsHandlePurged(codeSegment->fCodeSeg))
- HNoPurge(codeSegment->fCodeSeg);
- }
-
- codeSegment->fNextCodeSegment = NULL;
-
- if (prevSegPtr)
- prevSegPtr->fNextCodeSegment = codeSegment;
-
- #if qDebug
- codeSegment->fHighWater = FALSE;
- codeSegment->fEverLoaded = codeSegment->fSegLoaderLoaded;
- #endif
-
-
- prevSegPtr = codeSegment;
- }
-
- SetResLoad(oldResLoad);
- //###########################################
- #if !(qModelCFM && defined(__MWERKS__))
- //••• SRF #if is a hack to get it running
- GetUnloadedCodeSegment((ProcPtr)InitUMemory)->fResidentSeg = TRUE;// Main is always resident
-
- GetUnloadedCodeSegment((ProcPtr)UnloadAllSegments)->fResidentSeg = TRUE;// Utilities are always resident
- #endif
-
- #if qModelFarCode && !defined(__MWERKS__)
- {
- CCodeSegment* codeSegment = GetCodeSegmentFromName(CStr255("32-bit bootstrap"));
- if (codeSegment)
- codeSegment->fResidentSeg = TRUE;
- }
- #endif
-
- // Compute memory slop needed to respect the segments in the temp reserve
- short rsrcCnt = CountResources('seg!');
- for (short segRsrcIndex = 1; segRsrcIndex <= rsrcCnt; ++segRsrcIndex)
- {
- Handle h = GetIndResource('seg!', segRsrcIndex);
- temporaryReserve += AddSegSizes(h);
- ReleaseResource(h);
- }
-
- //
- // Catch the preloads added by the IDE that may not be included in the seg! resource above
- //
- {
- for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- {
- if (!codeSegment->fCanUnload && !codeSegment->fInTemporaryReserve)
- temporaryReserve += codeSegment->GetSize() + kHeapOverhead;
- }
- }
-
- } // DoInitUSegments
-
- //----------------------------------------------------------------------------------------
- // GetLoadedCodeSegment:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- // Shouldn't be unloaded
-
- CCodeSegment* GetLoadedCodeSegment(void* pc)
- {
- CCodeSegment* returnVal = NULL;
-
- for (CCodeSegment* codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- {
- if (codeSegment->ContainsAddress(pc))
- {
- returnVal = codeSegment;
- break;
- }
- }
-
- return returnVal; // default return
- } // GetLoadedCodeSegment
-
- //----------------------------------------------------------------------------------------
- // GetUnloadedCodeSegment: Gets CodeSegment from a Jump table address.
- //
- // Must be in Main segment because we call this in order to make the resident segment
- // resident.
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- CCodeSegment* GetUnloadedCodeSegment(ProcPtr aProc)
- {
- const short kJump = 0x4EF9; // if loaded then a JMP instruction
- const short kMove = 0x3F3C; // if unloaded then a Move instruction (seg# onto stack)
-
- // Check for load and unloaded state, otherwise we are not pointing
- // at a valid jump table entry.
-
- #if defined(__MWERKS__)
-
- // Function addresses taken segment 1 with Smart and Large model are not jump table addresses.
-
- static Size code1Start = 0;
- static Size code1End = 0;
- Size target = (Size)aProc;
-
- if (!code1Start) // the following is done once to get the "dimensions" of the first segment
- {
- Handle code1 = MAGet1Resource(kCode, 1);
- code1Start = (Size)StripAddress(*(Ptr*)code1);
- code1End = code1Start + InlineGetHandleSize(code1);
- }
- if ((target > code1Start) && (target < code1End))
- return GetCodeSegmentFromID(1);
-
- // Try again on the off chance that you might be using Small model.
- // Small model doesn't use a jump table which has the segment number for
- // references to segment 1.
- // The first 2 bytes are kJump and the next 4 bytes are the absolute address.
-
- if (*(short*)target == kJump)
- {
- target = *(Size*)(target + 2);
- if ((target > code1Start) && (target < code1End))
- return GetCodeSegmentFromID(1);
- }
-
- // Well we aren't in segment 1 so we are guaranteed a real jump table entry.
-
- if (*((const short *)aProc) == kJump || *((const short *)aProc) == (short)_LoadSeg)
- return GetCodeSegmentFromID(*((const short *)((const char *) aProc + 6)));
-
- #if qDebug
- ProgramBreak("GetUnloadedCodeSegment was not passed a valid function address.");
- #endif
- return NULL;
-
- #else
-
- // Non-Metrowerks
-
- #if qModelFarCode || qModelCFM
-
- // In a model far jump table entry the first two bytes are the segment number
- // whether the segment is loaded or not.
-
- if (*((const short *)aProc) == kJump || *((const short *)aProc) == (short)_LoadSeg)
- return GetCodeSegmentFromID(*((const short *)((const char *)aProc - 2)));
-
- #else
-
- // Classic 68K runtime
-
- if (*((const short *)aProc) == kJump) // loaded segment
- return GetCodeSegmentFromID(*((const short *)((const char *) aProc - 2)));
- else if (*((const short *)aProc) == kMove) // unloaded segment
- return GetCodeSegmentFromID(*((const short *)((const char *) aProc + 2)));
-
- #endif
-
- else
- {
- // routine that computed &proc was in same segment as the proc
- #if qDebug
- ProgramBreak("GetUnloadedCodeSegment was not passed an jump table address");
- #endif
- return NULL;
- }
-
- #endif // defined(__MWERKS__)
-
- } // GetUnloadedCodeSegment
-
- //----------------------------------------------------------------------------------------
- // PreloadHandler:
- //----------------------------------------------------------------------------------------
- #if qUseRTLib
- #pragma segment Main
-
- pascal short PreloadHandler(RTState* state)
- {
- short returnVal = 0;
-
- LoadMacAppSegment(state->fSegNo);
-
- if (oldPreLoadHandler)
- returnVal = ((HandlerType)oldPreLoadHandler)(state);
-
- return returnVal;
- } // PreloadHandler
- #endif
-
- //----------------------------------------------------------------------------------------
- // PostLoadMacAppSegment:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- // must be in Main segment
- // NOTE: this routine requires the pascal keyword because it is called from assembler
- // code that assumes pascal parameter passing conventions.
-
- pascal void PostLoadMacAppSegment()
- {
- long A5RegisterOnEntry = SetCurrentA5(); // can be called from trap patches
-
- if (pLoadSegCalledFromOwnApp)
- MAUseResFile(pOldResFile);
-
- SetA5(A5RegisterOnEntry);
- } // PostLoadMacAppSegment
-
- //----------------------------------------------------------------------------------------
- // PostloadHandler:
- //----------------------------------------------------------------------------------------
- #if qUseRTLib
- #pragma segment Main
-
- pascal short PostloadHandler(RTState* state)
-
- {
- short returnVal = 0;
-
- PostLoadMacAppSegment();
- if (oldPostLoadHandler)
- returnVal = ((HandlerType)oldPostLoadHandler)(state);
-
- return returnVal;
- } // PostloadHandler
- #endif
-
- //----------------------------------------------------------------------------------------
- // InitUSegments:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // Must be in main segment and called from main segment
-
- void InitUSegments()
- {
- // Install our memory hook for the grow zone proc
- // (Maybe the should be installed later, but this is closer to
- // the old way TotalTempSize worked.)
- gCodeSegmentGrowZoneHook.InsertFirst();
-
- long temporaryReserve;
- long lowSpaceRes;
-
- GetReserveSize(temporaryReserve, lowSpaceRes);
-
- DoInitUSegments(temporaryReserve);
-
- // Set up the LoadSeg patch
-
- #if qUseRTLib
- // Use the cool new RTLib so graciously
- // provided by Landon and Sandra
- RTPB anRTPB;
-
- // Install the preload handler
- anRTPB.fOperation = kRTSetPreLoad;
- anRTPB.fRTParam.fSegLoadParam.fUserHdlr = (SegLoadHdlrPtr)StripLong(PreloadHandler);
- if (Runtime(&anRTPB) != noErr)
- Failure(minErr, 0);
- oldPreLoadHandler = anRTPB.fRTParam.fSegLoadParam.fOldUserHdlr;
-
- // Install the postload handler
- anRTPB.fOperation = kRTSetPostLoad;
- anRTPB.fRTParam.fSegLoadParam.fUserHdlr = (SegLoadHdlrPtr)StripLong(PostloadHandler);
- if (Runtime(&anRTPB) != noErr)
- Failure(minErr, 0);
- oldPostLoadHandler = anRTPB.fRTParam.fSegLoadParam.fOldUserHdlr;
- #if !qModelCFM
- pSegLoadPatch.LookupOldTrapAddress(_LoadSeg);
- #endif
- #else
- #if !qModelCFM
- FailOSErr(pSegLoadPatch.PatchTrap(_LoadSeg, ALoadMacAppSeg));
- #endif
- #endif
-
- UnloadAllSegments(TRUE); // get init segment(s) out of middle of
- // heap, so SetReserveSize has maximum
- // space to work with
-
- LoadResidentSegments();
-
- SetReserveSize(temporaryReserve, lowSpaceRes);
-
- FailSpaceIsLow(); // couldn't get temorary reserve. Can't continue
- } // InitUSegments
-
-
- //----------------------------------------------------------------------------------------
- // LoadMacAppSegment:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // must be in Main segment
-
- pascal UniversalProcPtr LoadMacAppSegment(short segnum)
- {
- long A5RegisterOnEntry = SetCurrentA5(); // can be called from trap patches
-
- UniversalProcPtr loadMacAppSegment = NULL;
- #if !qModelCFM
- loadMacAppSegment = pSegLoadPatch.GetOldTrapAddr();// Where to go next
- #endif
-
- if (GetA5() != A5RegisterOnEntry)
- {
- // not called from our application… don't do patch behaviour. Thank you McSink!
- pLoadSegCalledFromOwnApp = FALSE;
- SetA5(A5RegisterOnEntry);
- }
- else
- {
- pLoadSegCalledFromOwnApp = TRUE;
- pOldResFile = MAUseResFile(gCodeRefNum);
- // Must set a global because we return
- // from this function and then forward to
- // the actual segment loader which should
- // also be pointing to the _now_ correct
- // resfile. When we get called back again
- // in PostLoadMacAppSegment we will
- // restore the old resFile as the current
- // resFile. Sorry about the global.
-
- GetCodeSegmentFromID(segnum)->LoadMacAppSegment();
- }
-
- return loadMacAppSegment;
- } // LoadMacAppSegment
-
- //----------------------------------------------------------------------------------------
- // LoadResidentSegments:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // Must be in Main segment
-
- void LoadResidentSegments()
- {
- short rsrcCnt = CountResources('res!');
- for (short resIndex = 1; resIndex <= rsrcCnt; ++resIndex)
- {
- Handle nameList = GetIndResource('res!', resIndex);
- SignedByte savedState = LockHandle(nameList);
-
- Ptr nameListPtr = *nameList;
- short numStrings = *((short*)nameListPtr);
- nameListPtr += sizeof(short);
-
- for (; numStrings; --numStrings, nameListPtr += *nameListPtr + 1)
- {
- CCodeSegment* codeSegment = GetCodeSegmentFromName((CStr255&)*nameListPtr);
- if (codeSegment)
- codeSegment->SetResidentSegment(TRUE);
- }
-
- HSetState(nameList, savedState);
- ReleaseResource(nameList);
- }
- } // LoadResidentSegments
-
- #if qDebug
- //----------------------------------------------------------------------------------------
- // CheckCallChain:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // must be in Main segment
-
- void CheckCallChain(const CStackFrame& frame,
- void* /* yourDataPtr */ )
- {
- void* pc = frame.GetReturnAddress();
-
- CCodeSegment* codeSegment = GetLoadedCodeSegment(pc);
- if (codeSegment && codeSegment->fSegLoaderLoaded && codeSegment->fCanUnload && !codeSegment->fResidentSeg)
- {
- fprintf(stderr, "Segment#: %d\n", codeSegment->fSegNum);
- ProgramBreak("you don't want to auto-unload a resident or preleoaded (!fCanUnload) segment!");
- }
- } // CheckCallChain
-
- #endif
-
- //----------------------------------------------------------------------------------------
- // UnloadAllSegments:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMemoryRes
-
- void UnloadAllSegments(Boolean andPurge)
- {
- #if qModelCFM && defined(__MWERKS__)
- //••• SRF hack to get it running
- return;
- #endif
-
- CheckRsrcUsage();
-
- if (gUnloadAllSegs)
- {
- #if qDebug
- CStackFrame stackFrame((void*)GetCurStackFramePtr());
- EachFrameDo(stackFrame, CheckCallChain, NULL);
- #endif
-
- short oldResFile = MAUseResFile(gCodeRefNum);
-
- for (CCodeSegment* codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
- {
- if (codeSegment->fSegLoaderLoaded && codeSegment->fCanUnload && !codeSegment->fResidentSeg)
- {
- Handle seg = codeSegment->fCodeSeg;
- if (seg && !InlineIsHandlePurged(seg) && codeSegment->fCanUnload)
- {
- codeSegment->Unload();
-
- if (andPurge)
- EmptyHandle(seg);
- // else
- // HNoPurge(seg);
- }
- }
- }
- MAUseResFile(oldResFile);
-
- if (gSegReport)
- ProgramReport(" *** Just unloaded all segments ***", gMemMgtBreak);
- }
- } // UnloadAllSegments
-
- #endif // qSegments
-
- //----------------------------------------------------------------------------------------
- // End of USegments.cp
-
- #pragma segment Inline
-